/*
 * @Author: kevin.huang 
 * @Date: 2018-07-27 23:24:11 
 * @Last Modified by: kevin.huang
 * @Last Modified time: 2019-05-07 21:07:03
 * Copyright (c): kevin.huang Released under MIT License
 */
/**
 * 2019-06-01 修复checkSingle配置引起的复选事件bug
 * 2019-05-16 修正展开父节点url为null还发生请求的bug
 * 2019-05-15 新增checkSingle配置，复选时候，不联动 父级、下级联动，默认值false;
 * 2019-05-04 新增 setCheckDatas(datas)适配mvvm联动
 * ***/
(function (global, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['$B', 'utils', 'toolbar'], function (_$B) {
            return factory(global, _$B);
        });
    } else {
        if(!global["$B"]){
            global["$B"] = {};
        }
        factory(global, global["$B"]);
    }
}(typeof window !== "undefined" ? window : this, function (window, $B) {    
    var $body;
    function _getBody(){
        if(!$body){
            $body = $(window.document.body).css("position", "relative");
        }
        return $body;
    }
    var defaultOpts = {
        data: null, //'数据'
        isTreeData: true,
        params: null, //远程加载时候附加的参数
        url: null, //请求数据的地址【如果有些请求参数是固定不变的，请去url中设置】
        textField: 'text', //菜单名称字段，默认为text
        idField: 'id', //菜单id字段,默认为id
        showLine: true, //显示连线
        checkSingle:false,//复选时候，不联动 父级、下级联动，默认值false
        extParamFiled: [], //异步懒加载时候，可以定义再传其他字段作为参数['filed1','filed2']，默认不设置只传pid
        canClickParent: true, //点击事件时，是否可以点击父节点
        nodeParentIcon: 'k_tree_fold_closed',//父节点图标关闭状态
        nodeParentOpenIcon: 'k_tree_fold_open',      //打开状态图标
        leafNodeIcon: 'k_tree_file_icon',                //子节点图标 
        chkEmptyIcon: 'k_tree_check_empty',            //不选
        chkAllIcon: 'k_tree_check_all',            //全选
        chkSomeIcon: 'k_tree_check_some',              //部分选
        fontIconColor: undefined,//字体图标颜色定义
        clickCheck: false, //是否点击复选       
        plainStyle: false, //true 为简单无图标样式
        forecePlainStyle:false,//强制简单样式
        onlyNodeData: false,//回调api中的参数是否只需要当前节点的数据（不带children）
        tree2list: true,//回调api中的参数是否转为列表类型
        checkbox: false, //是否需要选择框
        disChecked: false, //是否禁用复选框 默认false
        clickItemCls: 'k_tree_clicked_cls', //点击行颜色        
        toolbar: false, //是否需要工具栏,如果需要工具栏，则数据项中需要有toolbar工具栏组件的json
        methodsObject: 'methodsObject',//工具栏的按钮事件集合名
        onItemCreated: null, //项创建完成事件
        onTreeCreated: null,//树加载完成
        onClick: null, //function (data) { },//点击事件
        onloaded: null, //加载完成事件function (data) { }
        onOperated: null, //fn(pr) 工具栏任意事件都触发的事件
        onCheck: null, // function (data, params, checked) { } 选择事件,不建议注册onCheck事件，如果需要获取当前选择的数据，调用对象的getChecked即可
        onToggle: null //展开、收起回调
    };
    var loading = $("<li><div class='k_tree_item_wrap k_box_size'><div class='k_loading'></div></div></li>");
    function _makeTreeUi(_this, liTag, data, deep, params) {       
        var opts = _this.opts;
        var isLast = params.isLast;
        var isFirst = params.isFirst;
        var isParent = params.isParent;
        var $wrap = liTag.children("div");
        $wrap.data("data", data).data("params", params);       
        var $txt = $wrap.children(".k_tree_text");
        var isClosed = data.closed;
        if(!isClosed && data.children && data.children.length === 0){
            isClosed = true;
        }
        var clickNode, checkboxNode;
        var isFontIcon;
        if (isParent) {
            $wrap.attr("closed", isClosed);
        }
        var iconCls;
        if (opts.checkbox) {//需要checkbox
            iconCls = opts.chkEmptyIcon;
            if (data.checked) {
                iconCls = opts.chkAllIcon;
            }
            isFontIcon = iconCls.indexOf("fa-") > -1;
            if (isFontIcon) {
                checkboxNode = $('<div class="k_tree_check_box k_tree_font_icon k_tree_font_check"><i class="fa ' + iconCls + '"></i></div>').prependTo($wrap);
                if (opts.fontIconColor) {
                    checkboxNode.children("i").css("color", opts.fontIconColor);
                }
            } else {
                checkboxNode = $('<div class="k_tree_check_box k_tree_icon_img ' + iconCls + '"></div>').prependTo($wrap);
            }
            if (data.disChecked || _this.opts.disChecked) {
                checkboxNode.addClass("k_tree_check_disabled");
            } 
            checkboxNode.on("click", { _this: _this }, _this._checkBoxClick);
            
            if (!isParent && data.checked) {
                _this.triggerClickNodes.push(checkboxNode);
            }
        }
        if (!opts.plainStyle) {//需要图标
            if (isParent) {
                if (isClosed) {
                    iconCls = opts.nodeParentIcon;
                } else {
                    iconCls = opts.nodeParentOpenIcon;
                }
            } else {
                iconCls = opts.leafNodeIcon;
            }
            if (iconCls.indexOf("fa-") > -1) {
                clickNode = $('<div  class="k_tree_font_icon _node_"><i class="fa ' + iconCls + '"></i></div>').prependTo($wrap);
                if (opts.fontIconColor) {
                    clickNode.children("i").css("color", opts.fontIconColor);
                }
            } else {
                clickNode = $('<div class="k_tree_icon_img _node_ ' + iconCls + '"></div>').prependTo($wrap);
            }
        }
        if (opts.showLine) {//显示线样式
            if (isParent) {
                if (isClosed) {
                    if (isLast && isFirst) {//只有一个节点
                        if (deep === 0) {
                            iconCls = '_line_node_ k_tree_line_last_first_closed';
                        } else {
                            iconCls = '_line_node_ k_tree_line_last_closed';
                        }
                    } else if (isLast) {
                        iconCls = '_line_node_ k_tree_line_last_closed';
                    } else {
                        iconCls = '_line_node_ k_tree_line_closed';
                    }
                } else {
                    if (isLast && isFirst && deep === 0) {//只有一个节点
                        iconCls = '_line_node_ k_tree_line_last_first_open';
                    } else {
                        iconCls = '_line_node_ k_tree_line_open';
                        if (data.children.length === 0 && isLast) {
                            iconCls = '_line_node_ k_tree_line_last_empty_open';
                        }
                    }
                }
            } else {
                if (isLast && isFirst) {//只有一个节点
                    iconCls = 'k_tree_line_last';
                } else if (isFirst) {
                    iconCls = 'k_tree_line_cross';
                } else if (isLast) {
                    iconCls = 'k_tree_line_last';
                } else {
                    iconCls = 'k_tree_line_cross';
                }
            }
            var $tmp = $("<div class='k_tree_icon_img  " + iconCls + "'></div>").prependTo($wrap);
            if (isParent) {
                clickNode = $tmp;
            }
        }
        if (deep > 0) {
            var endCount = params["endCount"];
            var firstDiv = $wrap.children().first();
            var count = deep - endCount;
            var lineHtml, lastLineHtml;
            if (opts.showLine) {
                lineHtml = '<div class="k_tree_icon_img  k_tree_line_last"></div>';
                lastLineHtml = '<div class="k_tree_icon_img  k_tree_line_vertical"></div>';
            } else {
                lineHtml = '<div  class="k_tree_blank_div"></div>';
                lastLineHtml = '<div class="k_tree_blank_div"></div>';
            }
           
            if (isLast && endCount) {
                while (endCount > 0) {
                    firstDiv = $(lineHtml).insertBefore(firstDiv);
                    endCount--;
                }
            }
            while (count > 0) {
                firstDiv = $(lastLineHtml).insertBefore(firstDiv);
                count--;
            }            
        }
        if (clickNode) {
            clickNode.on("click", { _this: _this }, _this._parentNodeClick);            
            clickNode.on("mousedown",{ _this: _this }, _this._parentMouseDown);
        }
        if (opts.toolbar && data.toolbar) {            
            var toolbar = $("<div class='k_tree_tools_wrap' style='width:auto;display:inline-block;height:20px;margin-left:14px;'></div>").insertAfter($txt);
            var tOpt =  {
                style: 'plain', // plain / min  / normal /  big
                showText: true, // min 类型可以设置是否显示文字
                params: data,
                methodsObject: opts.methodsObject,
                buttons: data.toolbar,
                onOperated: opts.onOperated               
            };
            if(opts.iconColor){
            	tOpt.iconColor = opts.iconColor;
            }
            if(opts.fontColor){
            	tOpt.fontColor = opts.fontColor;
            }
            if(typeof opts.showText !== "undefined"){
                tOpt.showText = opts.showText;
            }
            new $B.Toolbar(toolbar,tOpt);
            delete data.toolbar;
        }
    }
    function _getLiHtmlTag(data, deep, params) {
        var _this = this;
        var opts = this.opts;
        var id = data.id,
            text = data.text;
        if (data.data[opts.idField]) {
            id = data.data[opts.idField];
        }
        if (data.data[opts.textField]) {
            text = data.data[opts.textField];
        }
        var liHtml = "<li id='" + id + "'><div  deep='" + deep + "' style='display:inline-block;min-width:100%;white-space:nowrap;' class='k_tree_item_wrap k_box_size'><div class='k_tree_text k_box_size'>" + text + "</div></div></li>";
        var liTag = $(liHtml);
        if (opts.onItemCreating) {
            opts.onItemCreating.call(liTag, data, deep, params);
        }
        _makeTreeUi(_this, liTag, data, deep, params);
        if (opts.onItemCreated) {
            opts.onItemCreated.call(liTag, data, deep, params);
        }
        liTag.on("click", { _this: _this }, _this._onClick);
        return liTag;
    }
    function _changeParentChkStatus(curNode, _this, isFontIcon) {
        if(_this.opts.checkSingle){
            return;
        }
        var deep = curNode.attr("deep");
        if (deep !== "0") {
            var data = curNode.data("data");
            var chkCount = data.checked ? 1 : 0;
            var $pli = curNode.parent();
            var siblings = $pli.siblings();
            var parentCls = _this.opts.chkEmptyIcon;
            var isParent = data.children !== undefined;
            var iconNode = curNode.children(".k_tree_check_box");
            if (isFontIcon) {
                iconNode = iconNode.children("i");
            }
            if (isParent) {
                if (iconNode.hasClass(_this.opts.chkSomeIcon)) {
                    parentCls = _this.opts.chkSomeIcon;
                }
            }
            siblings.each(function () {
                var $li = $(this);
                var chkBox = $li.children("div").children(".k_tree_check_box");
                if (isFontIcon) {
                    chkBox = chkBox.children("i");
                }
                if (chkBox.hasClass(_this.opts.chkAllIcon)) {
                    chkCount++;
                } else if (chkBox.hasClass("." + _this.opts.chkSomeIcon)) {
                    parentCls = _this.opts.chkSomeIcon;
                }
            });
            if (chkCount === siblings.length + 1) {
                parentCls = _this.opts.chkAllIcon;
            } else if (chkCount > 0) {
                parentCls = _this.opts.chkSomeIcon;
            }
            var $pul = $pli.parent();
            var parentNode = $pul.prev();
            iconNode = parentNode.children(".k_tree_check_box");
            if (isFontIcon) {
                iconNode = iconNode.children("i");
            }
            iconNode.removeClass(_this.opts.chkSomeIcon + " " + _this.opts.chkAllIcon + " " + _this.opts.chkEmptyIcon).addClass(parentCls);
            if (parentCls === _this.opts.chkAllIcon) {
                parentNode.data("data").checked = true;
            } else {
                parentNode.data("data").checked = false;
            }
            _changeParentChkStatus(parentNode, _this, isFontIcon);
        }
    }
    function _changeChildChkStatus(curNode, isFontIcon, ischeck, _this) {
        if(_this.opts.checkSingle){
            return;
        }
        var childrens = curNode.next().children();
        childrens.each(function () {
            var $li = $(this);
            var $wrap = $li.children("div");
            var iconNode = $wrap.children(".k_tree_check_box");
            if (isFontIcon) {
                iconNode = iconNode.children("i");
            }
            iconNode.removeClass(_this.opts.chkSomeIcon + " " + _this.opts.chkAllIcon + " " + _this.opts.chkEmptyIcon);
            if (ischeck) {
                iconNode.addClass(_this.opts.chkAllIcon);
                $wrap.data("data").checked = true;
            } else {
                iconNode.addClass(_this.opts.chkEmptyIcon);
                $wrap.data("data").checked = false;
            }
            var ul = $wrap.next();
            if (ul.length > 0) {
                _changeChildChkStatus($wrap, isFontIcon, ischeck, _this);
            }
        });
    }
    function _task(_this, ul, datas, deep, endCount) {
        _this.running++;
        setTimeout(function () {
            var data,
                children,
                $li, curEndCount = 0;
            var vUl = $("<ul />");
            for (var i = 0, len = datas.length; i < len; ++i) {
                var params = { isFirst: false, isLast: true, isParent: false };
                data = datas[i];
                children = data.children;
                curEndCount = 0;
                var needCount = false;
                var isClosed = data.closed;
                if (children) {
                    params.isParent = true;
                } else {
                    params.isParent = false;
                }
                if (i === 0) {
                    params.isFirst = true;
                } else {
                    params.isFirst = false;
                }
                if (i === datas.length - 1) {
                    params.isLast = true;
                    needCount = true;
                    if (params.isParent) {
                        curEndCount = 1 + endCount;
                        if (children.length > 0 && !data.closed) {
                            needCount = false;
                        }
                    }
                } else {
                    params.isLast = false;
                }
                if (needCount) {
                    params.endCount = endCount;
                } else {
                    params.endCount = 0;
                }
                $li = _getLiHtmlTag.call(_this, data, deep, params);
                $li.appendTo(vUl);
                if (children) {
                    _this._putParentRecord($li);
                    var ulStyle = "";
                    if (isClosed) {
                        ulStyle = "style='display:none;'";
                    }
                    var $childUl = $("<ul " + ulStyle + "/>").addClass("k_tree_ul").appendTo($li);
                    if (children.length > 0) {
                        _loopCreate.call(_this, $childUl, children, deep + 1, curEndCount);
                    }
                }else{
                    _this._putChildRecord($li);
                }
            }
            vUl.children().appendTo(ul);
            _this.running--;
            _this = undefined;
            ul = undefined;
            datas = undefined;
            deep = undefined;
            endCount = undefined;
        },0);
    }
    function _loopCreate(_ul, _datas, _deep, _endCount) {
        (_task)(this, _ul, _datas, _deep, _endCount);
    }
    /**根据数据创建树**/
    function _createByData(datas, deep) {
        var _this = this;
        _this.running = 0;
        _this.triggerClickNodes = [];
        var rootUl = this.jqObj;
        if ($.isPlainObject(datas)) {
            datas = [datas];
        }
        var data, children, $li, endCount, isClosed;
        for (var i = 0, len = datas.length; i < len; ++i) {
            var params = { isFirst: false, isLast: true, isParent: false };
            data = datas[i];
            isClosed = data.closed;
            children = data.children;
            endCount = 0;
            if (children) {
                params.isParent = true;
            } else {
                params.isParent = false;
            }
            if (i === 0) {
                params.isFirst = true;
            } else {
                params.isFirst = false;
            }
            if (i === datas.length - 1) {
                params.isLast = true;
                if (params.isParent) {
                    endCount = 1;
                }
            } else {
                params.isLast = false;
            }
            params["endCount"] = endCount;
            $li = _getLiHtmlTag.call(_this, data, deep, params);
            rootUl.append($li[0]);
            if (children) {
                this._putParentRecord($li);
                var ulStyle = "";
                if (isClosed) {
                    ulStyle = "style='display:none;'";
                }
                var $ul = $("<ul " + ulStyle + "/>").addClass("k_tree_ul").appendTo($li);
                if (children.length > 0) {
                    _loopCreate.call(_this, $ul, children, deep + 1, endCount);
                }
            }else{
                this._putChildRecord($li);
            }
        }
    }
    /**数据加载**/
    function _load($ul, params, callBackFn) {
        var _this = this;
        var opts = this.opts;
        var parentData,
            deep = 0;
        var $parent = $ul.prev("div.k_tree_item_wrap");
        if ($parent.length > 0) {
            parentData = $parent.data("data");
            deep = parseInt($parent.attr("deep")) + 1;
        }
        loading.find(".k_loading").css("margin-left", deep * 20);
        var $loading = loading.appendTo($ul);
        var ajaxOpts = {
            async: true,
            url: opts.url,
            data: params,
            ok: function (message, data,res) {              
                if(!_this.opts.isTreeData){
                    data = _this._formatData(data);
                }               
                if (parentData) {
                    var nodeParams = $parent.data("params");
                    var endCount = nodeParams.endCount;
                    _this.running = 0;
                    _this.triggerClickNodes = [];
                    parentData.children = data;
                    if(nodeParams.isLast){
                        endCount++;
                    }
                    _loopCreate.call(_this, $ul, data, deep, endCount);
                    _createCheckInterval.call(_this);
                } else {//根请求
                    opts.data = data;
                    _createByData.call(_this, data, deep);
                }
                if (opts.onloaded) {
                    setTimeout(function () {
                        opts.onloaded(data);
                    },10);
                }
            },
            fail: function (message) {
            },
            final: function (res) {
                $loading.remove();                
                if (callBackFn) {
                    setTimeout(function () {
                        callBackFn(res);
                    }, 200);
                }
                if (opts.requestfinal) {
                    opts.requestfinal();
                }
            }
        };
        this.ajax(ajaxOpts);
    }
    function _createCheckInterval() {
        var _this = this;
        var ivt = setInterval(function () {
            if (_this.running === 0) {
                clearInterval(ivt);
                _this.setRootUlWidth();
                var chkNode, isFontIcon, ul, li, trigger, siblings, $wrap, $ul;
                var resetNode = [];
                for (var i = 0, len = _this.triggerClickNodes.length; i < len; ++i) {
                    chkNode = _this.triggerClickNodes[i];
                    $wrap = chkNode.parent();
                    li = $wrap.parent();
                    if (li.data("skip")) {
                        continue;
                    }
                    isFontIcon = chkNode.hasClass("k_tree_font_check");
                    siblings = li.siblings();
                    trigger = true;
                    for (var j = 0, jlen = siblings.length; j < jlen; ++j) {
                        li = $(siblings[j]);
                        $ul = li.children("ul");
                        if ($ul.length > 0) {
                            if ($ul.children().length > 0) {
                                trigger = false;
                            }
                            break;
                        }
                    }
                    if (trigger) {
                        siblings.data("skip", true);
                        resetNode.push(siblings);
                        _changeParentChkStatus($wrap, _this, isFontIcon);
                    }
                }
                setTimeout(function () {
                    for (var k = 0, klen = resetNode.length; k < klen; ++k) {
                        resetNode[k].removeData("skip");
                    }
                    resetNode = undefined;
                },5);                
                if (_this.opts.onTreeCreated) {
                    _this.opts.onTreeCreated();
                }
            }
        },10);
    }
    var Tree = function (jqObj, opts) {
        $B.extend(this, Tree);
        this.parentNodesArray = [];
        this.childNodesArray = [];
        this.jqObj = jqObj.addClass("k_tree_ul k_tree_root k_box_size");//.css({"overflow-x":"auto","overflow-y":"visible"});
        this.jqObj.children().remove();
        this.opts = $.extend({}, {}, defaultOpts, opts);
        if (!this.opts.showLine && !this.opts.forecePlainStyle) {
            this.opts.plainStyle = false;
        }     
        this.clickedItem = undefined;
        if (this.opts.data && this.opts.data.length > 0) {
            if (!this.opts.isTreeData) {
                this.opts.data = this._formatData(this.opts.data);
            }
            _createByData.call(this, this.opts.data, 0);
            _createCheckInterval.call(this);
        } else if(this.opts.url && this.opts.url !== "") {
            var _this = this;
            _load.call(this, this.jqObj, { pid: "" }, function () {
                if (_this.jqObj.children().length === 0) {
                    var ofs = _this.jqObj.offset();
                    ofs.top = ofs.top + 2;
                    ofs.left = ofs.left + 12;
                    _this._tipNotDate(ofs);
                }
            });
        }  
        this.jqObj.data("treeIns",this);     
    };
    Tree.prototype = {
        setRootUlWidth:function(){
            var _this = this;
            var minWidth = this.jqObj.parent().width();
            this.minWidth = minWidth;
            this.jqObj.children().each(function(){
                var li = $(this);
                var w = 0 ;
                li.children("div").children().each(function(){
                    w = $(this).outerWidth() + w;                     
                });
                if(w > _this.minWidth){
                    _this.minWidth = w;
                }
                _this._loopVisiableUl(li.children("ul"));
            });
            this.jqObj.css("min-width" , this.minWidth);
        },
        _loopVisiableUl:function(ul){
            if(ul.length > 0 && ul.css("display") !== "none"){
                var _this = this;
                ul.children().each(function(){
                    var li = $(this);
                    var w = 0 ;
                    li.children("div").children().each(function(){
                        w = $(this).outerWidth() + w;                     
                    });
                    if(w > _this.minWidth){
                        _this.minWidth = w;
                    }
                    _this._loopVisiableUl(li.children("ul"));
                });   
            }
        },
        /**普通列表转为tree格式***/
        _formatData: function (list, pid) {
            var res = [];
            if (pid) {
            } else {
                for (var i = 0, len = list.length; i < len; ++i) {
                    var d = list[i];
                    res.push({
                        id: d[this.opts.idField],
                        text: d[this.opts.textField],
                        data: d
                    });
                }
            }
            return res;
        },
        _tree2list: function (resultArray, treeData, filterFn) {
            var _this = this;
            var data = {};
            var isParent = typeof treeData.children !== "undefined";
            var childrens = [];
            Object.keys(treeData).forEach(function (key) {
                var v = treeData[key];
                var needed = true;
                if (filterFn) {
                    needed = filterFn(key, isParent, treeData);
                }
                if (key === "children") {
                    childrens = v;
                } else {
                    if (needed) {
                        if ($.isPlainObject(v)) {
                            v = $.extend(true, {}, v);
                        }
                        data[key] = v;
                    }
                }
            });
            if (!$.isEmptyObject(data)) {
                resultArray.push(data);
            }
            if (childrens && childrens.length > 0) {
                for (var i = 0, len = childrens.length; i < len; ++i) {
                    _this._tree2list(resultArray, childrens[i], filterFn);
                }
            }
        },
        _getNodeData: function ($wrap) {
            var params = $wrap.data("params");
            var srcData = $wrap.data("data");
            var data, _this = this;
            if (params.isParent) {
                if (_this.opts.onlyNodeData) {
                    data = {isParent:true};
                    Object.keys(srcData).forEach(function (key) {
                        if (key !== "children") {
                            var v = srcData[key];
                            if ($.isPlainObject(v)) {
                                v = $.extend(true, {}, v);
                            }
                            data[key] = v;
                        }
                    });
                    if (_this.opts.tree2list) {
                        data = [data];
                    }
                } else if (_this.opts.tree2list) {
                    var list = [];
                    _this._tree2list(list, srcData);
                    data = list;
                } else {
                    data = $.extend(true, {}, srcData);
                }
            } else {
                data = $.extend(true, {}, srcData);
                if (_this.opts.tree2list) {
                    data = [data];
                }
            }
            return data;
        },
        _onClick: function (e) {          
            var _this = e.data._this;
            var isClickFn = typeof _this.opts.onClick === "function";
            if(isClickFn || _this.opts.clickCheck){
                var $node = $(this);
                var $wrap = $node.children("div");
                var params = $wrap.data("params");
                if (!_this.opts.canClickParent && params.isParent) {
                    return false;
                }
                if (_this.clickedItem) {
                    _this.clickedItem.removeClass(_this.opts.clickItemCls);
                }
                _this.clickedItem = $wrap.addClass(_this.opts.clickItemCls);                
                if (_this.opts.clickCheck) {
                    var chkBox = $wrap.children(".k_tree_check_box");
                    if (!chkBox.hasClass("k_tree_check_disabled")) {
                        chkBox.trigger("click");
                    }
                } 
                if(isClickFn){
                    var data = _this._getNodeData($wrap);
                    _this.opts.onClick.call($node, data, params);
                }
            }            
            return false;
        },
        _checkBoxClick: function (e) {
            var _this = e.data._this;
            var $node = $(this);
            if(!e.isTrigger && $node.hasClass("k_tree_check_disabled")){
                return;
            }
            var $wrap = $node.parent();
            var params = $wrap.data("params");
            if (!_this.opts.canClickParent && params.isParent) {
                return false;
            }
            var data = $wrap.data("data");
            var isParent = $wrap.next().length > 0;
            var $i = $node.children("i");
            var isFontIcon = $node.hasClass("k_tree_font_icon");
            if ($i.length > 0) {
                $node = $i;
            }
            if (data.checked) {
                $node.removeClass(_this.opts.chkAllIcon).removeClass(_this.opts.chkSomeIcon).addClass(_this.opts.chkEmptyIcon);
                data.checked = false;
            } else {
                $node.removeClass(_this.opts.chkEmptyIcon).removeClass(_this.opts.chkSomeIcon).addClass(_this.opts.chkAllIcon);
                data.checked = true;
            }
            if(!_this.opts.checkSingle){
                if (isParent) {
                    _changeParentChkStatus($wrap, _this, isFontIcon);
                    _changeChildChkStatus($wrap, isFontIcon, data.checked, _this);
                } else {
                    _changeParentChkStatus($wrap, _this, isFontIcon);
                } 
            }          
            if (_this.opts.onCheck && !_this._noNotify) {
                var resData = _this._getNodeData($wrap);
                _this.opts.onCheck(resData, params, data.checked);              
            }
            if(typeof _this.onWatcher === "function"){//配合动态双向表单功能
                _this.onWatcher.call(_this);
            }
            return false;
        },
        _changeNodeUi: function ($node) {
            var $wrap = $node.parent();
            var $li = $wrap.parent();
            var isLast = $li.next().length === 0;
            var nextIcon, fixCount = 0, parentNode, $ul, $tmp;
            if ($node.hasClass("_node_")) {
                nextIcon = $node;
            } else {
                nextIcon = $node.next("._node_");
            }
            var $i = nextIcon.children("i");
            var isClosed = $wrap.next().css("display") === "none";
            if ($i.length > 0) {
                nextIcon = $i;
            }
            if (isLast && this.opts.showLine) {
                $ul = $li.parent();
                parentNode = $ul.parent();
                while ($ul[0] !== this.jqObj[0]) {
                    if (parentNode.next().length === 0) {
                        fixCount++;
                        $ul = parentNode.parent();
                        parentNode = $ul.parent();
                    } else {
                        break;
                    }
                }
            }
            if ($node.hasClass("_node_")) {
                if (isClosed) {
                    nextIcon.removeClass(this.opts.nodeParentOpenIcon).addClass(this.opts.nodeParentIcon);
                } else {
                    nextIcon.removeClass(this.opts.nodeParentIcon).addClass(this.opts.nodeParentOpenIcon);
                }
            } else {
                if (isClosed) {
                    $node.removeClass("k_tree_line_open k_tree_line_last_empty_open");
                    if (isLast) {
                        $node.addClass("k_tree_line_last_closed");
                        $tmp = $node;
                        while (fixCount > 0) {
                            $tmp = $tmp.prev().removeClass("k_tree_line_vertical").addClass("k_tree_line_last");
                            fixCount--;
                        }
                    } else {
                        $node.addClass("k_tree_line_closed");
                    }
                    nextIcon.removeClass(this.opts.nodeParentOpenIcon).addClass(this.opts.nodeParentIcon);
                } else {
                    $node.removeClass("k_tree_line_last_closed k_tree_line_closed");
                    $node.addClass("k_tree_line_open");
                    nextIcon.removeClass(this.opts.nodeParentIcon).addClass(this.opts.nodeParentOpenIcon);
                    $tmp = $node;
                    while (fixCount > 0) {
                        $tmp = $tmp.prev().removeClass("k_tree_line_last").addClass("k_tree_line_vertical");
                        fixCount--;
                    }
                }
            }
        },
        _putParentRecord:function(li){
            this.parentNodesArray.push(li);
        },
        _putChildRecord:function(li){
            this.childNodesArray.push(li);
        },
        _parentMouseDown:function(e){
            return false;
        },
        /**
         * 节点收放事件
         * **/
        _parentNodeClick: function (e) {            
            var $node = $(this);
            if (!$node.data("busy")) {
                var $wrap = $node.parent();
                var nodeData = $wrap.data("data");
                var _this = e.data._this;
                var id = _this.opts.idField === "id" ? nodeData.id : nodeData.data[_this.opts.idField];
                var ul = $wrap.next();
                var notChildren = ul.children().length === 0;
                $node.data("busy", true);
                var ofs = $node.offset();
                var isClosed = $wrap.attr("closed");
                if (isClosed === "true") {
                    if (notChildren &&  _this.opts.url && _this.opts.url !== "") {
                        var params = { pid: id };
                        for (var i = 0, len = _this.opts.extParamFiled.length; i < len; ++i) {
                            params[_this.opts.extParamFiled[i]] = nodeData.data[_this.opts.extParamFiled[i]];
                        }
                        ul.show();
                        _load.call(_this, ul, params, function (data) {
                            $wrap.removeAttr("closed");
                            $node.removeData("busy");
                            _this._changeNodeUi($node);
                            if (ul.children().length === 0) {
                                $node.trigger("click");
                                _this._tipNotDate(ofs);
                            }
                        });
                    } else {
                        ul.slideDown(150, function () {
                            $wrap.removeAttr("closed");
                            $node.removeData("busy");
                            _this._changeNodeUi($node);
                            _this.setRootUlWidth();
                            if (notChildren) {
                                $node.trigger("click");
                                _this._tipNotDate(ofs);
                            }
                            if(_this.opts.onToggle){
                                _this.opts.onToggle("show");
                            }
                        });
                    }
                } else {
                    ul.slideUp(150, function () {
                        $wrap.attr("closed", true);
                        $node.removeData("busy");
                        _this._changeNodeUi($node);
                        _this.setRootUlWidth();
                        if(_this.opts.onToggle){
                            _this.opts.onToggle("hide");
                        }
                    });
                }
            }
            return false;
        },
        _tipNotDate: function (ofs) {
            var tip = $("<div style='width:auto;position:absolute;top:-1000px;left:" + ofs.left + "px' class='k_tree_empty_tip k_box_size'>" + $B.config.noData + "</div>").appendTo(_getBody());
            tip.css("top", ofs.top);
            setTimeout(function () {
                tip.fadeOut(450, function () {
                    tip.remove();
                });
            }, 1200);
        },
        /**
        * 重新加载数据
        @param target:节点树ul对象,可以用于只加载某个子节点	,可不传值
        @param args={p:1} 查询参数		
        ****/
        reload: function (target,args) { 
            var ul,params = {};           
            if(arguments.length === 1){
                if($.isPlainObject(target)){
                    ul = this.jqObj;
                    params = target;
                }else{
                    ul = target;                    
                }
            }else{
                ul = target;
                params = args;
            }
            var isRoot = ul[0] === this.jqObj[0];
            var _this = this , ofs;
            if(isRoot){
                ul.children().remove();
            }else{
                var pid = ul.parent().attr("id");
                params["pid"] = pid;
            }
            ul.children().remove();
            _load.call(this, ul, params, function (data) {
                _this.clickedItem = undefined;
                if(isRoot){
                    if (_this.jqObj.children().length === 0) {
                        ofs = _this.jqObj.offset();
                        ofs.top = ofs.top + 2;
                        ofs.left = ofs.left + 12;
                        _this._tipNotDate(ofs);
                    }                   
                }else{                    
                    var $wrap = ul.prev();
                    $wrap.removeAttr("closed");
                    var $node = $wrap.children("._line_node_");
                    $node.removeData("busy");
                    ofs = $node.offset();
                    _this._changeNodeUi($node);
                    if (ul.children().length === 0) {
                        $node.trigger("click");
                        _this._tipNotDate(ofs);
                    }
                }
            });
        },
        reset:function(){
            if(this.clickedItem){
                this.clickedItem.removeClass(this.opts.clickItemCls);
                this.clickedItem = undefined;
            }
            if(this.opts.checkbox){
                for(var i = 0 ,len = this.childNodesArray.length ; i < len ;++i){
                    var li = this.childNodesArray[i];
                    var wrap = li.children("div");                   
                    if(wrap.data("data").checked){
                        wrap.children(".k_tree_check_box").trigger("click");
                    }                
                }
            }           
        },
        /***
        * 更新节点
        @param $node	节点jq对象
        @param data	更新的数据
        * ***/
        updateNode: function ($node, data) { },
        /**获取点击的项**/
        getClickItem: function () {
            if (this.clickedItem) {
                return this._getNodeData(this.clickedItem);
            }
        },
        /**
         *{
            onlyId: false,
            onlyChild: false
         }
         * **/
        getCheckedData: function (params) {
            var onlyId = false,
                onlyChild = false;
            if (params) {
                if (typeof params.onlyId !== 'undefined') {
                    onlyId = params.onlyId;
                }
                if (typeof params.onlyChild !== 'undefined') {
                    onlyChild = params.onlyChild;
                }
            }
            var res = [];
            var _this = this;
            var datas = this.opts.data;
            var filterFn = function (key, isParent, nodeData) {
                if (!nodeData.checked) {
                    return false;
                }
                var go = true;
                if (onlyId) {
                    if (key !== _this.opts.idField) {
                        go = false;
                    }
                }
                if (onlyChild && isParent) {
                    go = false;
                }
                return go;
            };
            for (var i = 0, len = datas.length; i < len; ++i) {
                this._tree2list(res, datas[i], filterFn);
            }
            return res;
        },
        getParentList:function(nodeEl){
            var tmp = [];       
            tmp.push(nodeEl.data("data"));   
            var parentUl =  nodeEl.parent().parent();
            while(parentUl.length > 0 && parentUl.hasClass("k_tree_ul")){
                if(parentUl.hasClass("k_tree_root")){
                    break;
                }
                nodeEl = parentUl.prev();
                tmp.push(nodeEl.data("data"));   
                parentUl =  nodeEl.parent().parent();
            } 
            return tmp.reverse();
        },
        /**
         * 设置勾选/选择的数据，适配mvvm联动
         * datas = []; datas = "id1,id2,id3"
         * ***/
        setCheckDatas:function(datas){ 
            var _this = this; 
            if(this.running > 0){
                setTimeout(function(){
                    _this.setCheckDatas(datas);
                },200);
                return;
            }            
            if(typeof datas === "string"){
                if(datas === ""){
                    datas = [];
                }else{
                    datas = datas.split(",");
                }
            }
            var dataMap = {};
            for(var i = 0 ,len = datas.length ; i < len ;++i){
                dataMap[datas[i]] = true;
            }            
            this._noNotify = true;
            this.loopRoot(function($li){
                var $it = $li.children("div");
                var data = $it.data("data");
                var id = $li.attr("id");
                if(data.checked ){//如果是复选状态，则检查dataMap                    
                    if(!dataMap[id]){
                        $it.children(".k_tree_check_box").trigger("click");
                    }                   
                }else if(dataMap[id]){
                    $it.children(".k_tree_check_box").trigger("click");
                }
            });            
            this._noNotify = false;
        },
        /**
         * 设置点击的项，适配mvvm联动
         * **/
        setClickedItem:function(id){
            id = id + "";
            var _this = this;
            if(this.running > 0){
                setTimeout(function(){
                    _this.setClickedItem(id);
                },200);
                return;
            }  
            if(this.clickedItem){
                this.clickedItem.removeClass("k_tree_clicked_cls");
            }
            var hasFined = false;
            this.loopRoot(function($li){
                if(hasFined){
                    return true;
                }
                var $it = $li.children("div");
                if($li.attr("id") === id){
                    _this.clickedItem = $it.addClass("k_tree_clicked_cls");
                    hasFined = true;
                    return true;
                }
            });
        },
        loopRoot:function(onLoopFn){
            var _this = this;
            this.jqObj.children().each(function(){
                var $li = $(this);              
                var isBreak = onLoopFn($li);
                if(isBreak){
                    return false;
                }
                var childUl = $li.children("ul");
                if(childUl.length > 0){//子元素
                    _this.loopChild(childUl.children(),onLoopFn);
                }
            });
        },
        loopChild:function(childs,onLoopFn){
            var _this = this;
            childs.each(function(){
                var $li = $(this);
                var isBreak = onLoopFn($li);
                if(isBreak){
                    return false;
                }
                var childUl =  $li.children("ul");
                if(childUl.length > 0){//子元素
                    _this.loopChild(childUl.children(),onLoopFn);
                }
            });
        }
    };
    $B["Tree"] = Tree;
    return Tree;
}));